package models

import (
	"errors"
	"fmt"

	//"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"

	//"strconv"
	"bufio"
	"os"
	"strings"
	"time"

	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/validation"

	//"github.com/satori/go.uuid"
	admlib "xwaf_admin/xadmin/src/lib"

	"github.com/tidwall/gjson"
)

type Xf_waf_riskip struct {
	Id           int64  `json:"id"`
	Ip           string `json:"ip" valid:"Required"`
	Is_malicious string `json:"is_malicious"`
	Risk_type    string `json:"risk_type"` //waf,limit,trust[太平洋或CDN的IP]
	Tag          string `json:"tag"`
	City         string `json:"city"`
	Remarks      string `json:"remarks"`
	Updatetime   string `json:"updatetime"`
	Createtime   string `json:"createtime"`
}

type Riskip struct {
	Ip           string `json:"ip"`
	Risk_type    string `json:"risk_type"`
	Is_malicious bool   `json:"is_malicious"`
}

var OtherTrustIpFile = admlib.GetConfigString("OtherTrustIpFile")
var OtherTrustIpList = []string{}

func init() {
	orm.Debug = true
	orm.RegisterModel(new(Xf_waf_riskip))
	//load file
	ReadIpFileToArry(OtherTrustIpFile)
}

func ReadIpFileToArry(filepath string) {
	if filepath != "" {
		file, err := os.Open(filepath)
		if err != nil {
			//fmt.Println(err)
			log.Printf("[WARN] load ctyun source ip list file,Fail:%s\n", err)
		}
		defer file.Close()
		bi := bufio.NewReader(file)
		for {
			line, err := bi.ReadString('\n')
			if err != nil {
				break // 读取完成整个文件退出循环
			}
			//log.Printf("%s", line)
			OtherTrustIpList = append(OtherTrustIpList, strings.TrimSpace(line))
		}
	}
}

func checkRiskIp(u *Xf_waf_riskip) (err error) {
	valid := validation.Validation{}
	b, _ := valid.Valid(&u)
	if !b {
		for _, err := range valid.Errors {
			log.Println(err.Key, err.Message)
			return errors.New(err.Message)
		}
	}
	return nil
}

//List
//func GetXf_waf_blackipList(appname, ruletype string, id int64) (xf_waf_rule []orm.Params, count int64) {
func GetXf_waf_riskipList(is_malicious, tag, ip string, id, page, page_size int64) (xfr []Xf_waf_riskip, count int64) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Xf_waf_riskip))
	cond := orm.NewCondition()
	var offset int64
	if page <= 1 {
		offset = 0
	} else {
		offset = (page - 1) * page_size
	}
	if id > 0 {
		cond = cond.And("id", id)
	}
	if ip != "" {
		//cond = cond.And("ip", ip)
		ipArry := strings.Split(ip, ".")
		ipseg := ip
		if len(ipArry) == 4 {
			ipseg = ipArry[0] + "." + ipArry[1] + "." + ipArry[2]
		}
		cond = cond.And("ip__contains", ipseg)
	}
	if is_malicious != "" {
		cond = cond.And("is_malicious", is_malicious)
	}
	if tag != "" {
		cond = cond.And("tag__contains", tag)
	}
	qs = qs.SetCond(cond)
	qs.Limit(page_size, offset).OrderBy("-id").All(&xfr)
	//qs.All(&xfr)
	count, _ = qs.Count()
	return xfr, count
}

func GetRiskIp(cfgv string) (stu []*Riskip, count int64) {
	o := orm.NewOrm()
	var sqlstr string
	if cfgv == "0" || cfgv == "" {
		sqlstr = fmt.Sprintf("SELECT ip,is_malicious,risk_type FROM xf_waf_riskip WHERE risk_type != 'trust'")
	} else {
		sTime := time.Now().Add(-1 * time.Hour).Format("2006-01-02 15:04:05")
		sqlstr = fmt.Sprintf("SELECT ip,is_malicious,risk_type FROM xf_waf_riskip WHERE updatetime > '%s'", sTime)
	}
	num, err := o.Raw(sqlstr).QueryRows(&stu)
	if err == nil && num > 0 {
		return stu, num
	}
	return nil, 0
}

//添加
func AddXf_waf_riskip(u *Xf_waf_riskip) (int64, error) {
	if err := checkRiskIp(u); err != nil {
		return 0, err
	}
	o := orm.NewOrm()
	iplist := strings.Split(u.Ip, ",")
	var num int64
	for _, ip := range iplist {
		Xf_waf_riskip := new(Xf_waf_riskip)
		Xf_waf_riskip.Ip = ip
		Xf_waf_riskip.Remarks = u.Remarks
		Xf_waf_riskip.Is_malicious = u.Is_malicious
		if u.Risk_type == "" {
			u.Risk_type = "limit"
		}
		Xf_waf_riskip.Risk_type = u.Risk_type
		Xf_waf_riskip.Tag = u.Tag
		Xf_waf_riskip.City = u.City
		//ctm := u.Updatetime
		//if ctm == "" {
		ctm := time.Now().Format("2006-01-02 15:04:05")
		//}
		Xf_waf_riskip.Createtime = time.Now().Format("2006-01-02 15:04:05")
		Xf_waf_riskip.Updatetime = ctm
		_, err := o.Insert(Xf_waf_riskip)
		if err == nil {
			num += 1
		}
	}
	if num > 0 {
		UpdateConfigTime("sys")
	}
	return num, nil
}

//通过微步在线查询IP的行情
func QueryRiskIp(ip string) (string, string, string, error) {
	riskIpIsQuery := admlib.GetConfigString("riskIpIsQuery")
	if riskIpIsQuery != "true" {
		return "", "", "", fmt.Errorf("riskIpIsQuery is false")
	}
	riskIpApi := admlib.GetConfigString("riskIpApi")
	resp, err := http.Get(riskIpApi + "&resource=" + ip)
	body, err := ioutil.ReadAll(resp.Body)
	gp := gjson.ParseBytes(body)
	//log.Printf("[INFO] Query Reskip:%s\n", string(body))
	if gp.Get("response_code").Int() == 0 {
		ismalicious := gp.Get("data").Get("is_malicious").Bool()
		updatetime := gp.Get("data").Get("update_time").String()
		tags := gp.Get("data").Get(ip).Get("judgments").Array()
		var tagArry []string
		for _, vv := range tags {
			tagArry = append(tagArry, vv.String())
		}
		return fmt.Sprintf("%v", ismalicious), strings.Join(tagArry, ","), updatetime, nil
	}
	return "", "", "", err
}

func DelRiskIpById(id int64) (int64, error) {
	o := orm.NewOrm()
	status, err := o.Delete(&Xf_waf_riskip{Id: id})
	return status, err
}

func EditRiskIp(id, key, value string) (int64, error) {
	o := orm.NewOrm()
	sqlstr := fmt.Sprintf("UPDATE xf_waf_riskip SET %s = '%s' WHERE id = %s", key, value, id)
	res, err := o.Raw(sqlstr).Exec()
	if err == nil {
		num, _ := res.RowsAffected()
		UpdateConfigTime("sys")
		log.Printf("[INFO] EditRiskIp affected nums:%d\n", num)
		return num, nil
	}
	return 0, err
}

//临时更新IP城市信息
func UpdateCityByIp(ip string) (int64, error) {
	o := orm.NewOrm()
	cityinfo := GetIpCity(ip)
	sqlstr := fmt.Sprintf("UPDATE xf_waf_riskip SET city = '%s' WHERE ip = '%s'", cityinfo, ip)
	res, err := o.Raw(sqlstr).Exec()
	if err == nil {
		num, _ := res.RowsAffected()
		log.Printf("[INFO] UpdateCityByIp affected nums:%d\n", num)
		return num, nil
	}
	return 0, err
}

//根据OtherTrustIpFile IP的网段来进行判断是否信任IP
func JudgeTrustIpFromFile(ip string) bool {
	netip := net.ParseIP(ip)
	for _, netseg := range OtherTrustIpList {
		_, ipNet, _ := net.ParseCIDR(netseg)
		if ipNet.Contains(netip) {
			return true
			break
		}
	}
	return false
}

//从riskip表里搜索白名单的IP进行C段判断："1.1.1.1"
func JudgeOkIpFromRiskIp(ip string) (xfr []Xf_waf_riskip, count int64) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Xf_waf_riskip))
	cond := orm.NewCondition()
	if ip != "" {
		//cond = cond.And("ip", ip)
		ipArry := strings.Split(ip, ".")
		ipseg := ip
		if len(ipArry) == 4 {
			ipseg = ipArry[0] + "." + ipArry[1] + "." + ipArry[2]
		}
		cond = cond.And("ip__contains", ipseg)
	}
	cond = cond.And("is_malicious", "false")
	cond = cond.And("tag__contains", "WhitelistIP")

	qs = qs.SetCond(cond)
	qs.All(&xfr)
	//qs.All(&xfr)
	count, _ = qs.Count()
	return xfr, count
}

//查询IP城市信息
func GetIpCity(ip string) string {
	getipUrl := fmt.Sprintf("http://127.0.0.1:6002/metric/v1/getip?ip=%s", ip)
	log.Println(getipUrl)
	res, err := http.Get(getipUrl)
	if err != nil {
		log.Printf("[ERROR] call getip Api fail:%s\n", err)
		return ""
	}
	defer res.Body.Close()
	bodyBytes, _ := ioutil.ReadAll(res.Body)
	log.Println(string(bodyBytes))
	gpb := gjson.ParseBytes(bodyBytes)
	info := fmt.Sprintf("%s%s%s%s", gpb.Get("country").String(), gpb.Get("region").String(), gpb.Get("city").String(), gpb.Get("isp").String())
	info = strings.Replace(info, "0", "", -1)
	//info = strings.Replace(info, ",,", "", -1)
	//return strings.TrimRight(info, ",")
	return info
}
